package luke.audio.metadata;

import luke.audio.analyzer.BPMDetector;
import luke.audio.analyzer.BeatDetector;
import luke.audio.analyzer.AlignedBeatResult;
import luke.audio.analyzer.UniversalAudioDecoder;
import luke.core.utils.JsonUtils;
import luke.ui.dialogs.DonationDialog;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 歌曲元数据提取器类，用于处理音频文件并提取歌曲元数据
 * 包括BPM、音频时长和鼓点位置等信息
 */
public class SongMetadataExtractor {
    private Map<File, Song> songData = new HashMap<>();

    private List<File> audioFiles = new ArrayList<>();
    private SwingWorker worker;
    private int lastPriority = 0;

    // 任务调度器实例
    private final TaskScheduler taskScheduler = TaskScheduler.getInstance();

    public Map<File, Song> getSongData() {
        return songData;
    }

    public void setSongData(Map<File, Song> songData) {
        this.songData = songData;
    }

    public List<File> getAudioFiles() {
        return audioFiles;
    }

    public void setAudioFiles(List<File> audioFiles) {
        this.audioFiles = audioFiles;
    }

    //实现单例模式
    private static SongMetadataExtractor instance;

    private SongMetadataExtractor() {
    }

    public static SongMetadataExtractor getInstance() {
        if (instance == null) {
            instance = new SongMetadataExtractor();
        }
        return instance;
    }

    /**
     * 提取音频文件的元数据（优先从JSON文件读取）
     *
     * @param audioFile 音频文件
     * @return Song对象，包含音频信息和鼓点偏移量
     */
    public Song extractMetadata(File audioFile) throws IOException {
        // 检查同级目录是否有同名的JSON文件
        String jsonFilePath = getJsonFilePath(audioFile);
        File jsonFile = new File(jsonFilePath);

        if (jsonFile.exists()) {
            // 如果存在JSON文件，则直接从JSON读取
            try {
                return JsonUtils.readFromJson(jsonFilePath, Song.class);
            } catch (IOException e) {
                System.err.println("读取JSON文件失败: " + e.getMessage());
                // 如果读取失败，继续执行正常的元数据提取流程
            }
        }

        // 如果没有JSON文件或读取失败，则执行正常的元数据提取流程
        return extractMetadataDirectly(audioFile);
    }

    /**
     * 直接提取音频文件的元数据（不读取JSON文件）
     *
     * @param audioFile 音频文件
     * @return Song对象，包含音频信息和鼓点偏移量
     */
    public Song extractMetadataDirectly(File audioFile) throws IOException {
        // 检查线程是否被中断
        if (Thread.currentThread().isInterrupted()) {
            throw new IOException("元数据提取被取消");
        }

        // 执行正常的元数据提取流程
        Song song = new Song();
        song.setAudioPath(audioFile.getAbsolutePath());
        song.setFileName(audioFile.getName());
        try {
            // 检查线程是否被中断
            if (Thread.currentThread().isInterrupted()) {
                throw new InterruptedException("BPM检测被取消");
            }

            // 使用BPMDetector基于频谱数据检测BPM
            BPMDetector detector = new BPMDetector(audioFile);

            // 检查线程是否被中断
            if (Thread.currentThread().isInterrupted()) {
                throw new InterruptedException("BPM检测被取消");
            }

            // 获取筛选后的BPM候选值（最多2个）
            List<Double> candidateBPMs = detector.getAllBpmCandidates();
            System.out.println("检测到的BPM候选值：" + candidateBPMs);
            song.setDuration(detector.getAudioDurationMs());
            UniversalAudioDecoder.AudioData audioData = detector.getAudioData();

            // 检查线程是否被中断
            if (Thread.currentThread().isInterrupted()) {
                throw new InterruptedException("鼓点检测被取消");
            }

            // 使用新的鼓点检测方法（支持多个BPM值）
            BeatDetector beatDetector = new BeatDetector(detector);
            AlignedBeatResult alignedResult = beatDetector.detectBeatPositions(detector, false);

            double finalBPM = alignedResult.getBpm();
            // 保存偏移量
            int beatOffset = 0;
            // 检查beatPositions是否为空，避免IndexOutOfBoundsException
            if (!alignedResult.getBeats().isEmpty()) {
                // 保存偏移量（理论鼓点的第一个位置）
                beatOffset = alignedResult.getBeats().get(0);

                // 根据您的说明，实际应该计算理论鼓点第一个位置相对于节拍间隔的偏移
                // 计算节拍间隔（毫秒）
                double beatIntervalMs = 60000.0 / finalBPM;

                // 计算第一个鼓点位置相对于节拍间隔的偏移量
                if (beatIntervalMs > 0) {
                    beatOffset = (int) (beatOffset % beatIntervalMs);
                }

                // 确保偏移量为正数且合理
                if (beatOffset < 0) {
                    beatOffset = (int) ((beatOffset % beatIntervalMs) + beatIntervalMs);
                }
            }

            song.setBpm(finalBPM); // 保存优化后的bpm
            song.setBeatOffset(beatOffset); // 保存偏移量
        } catch (InterruptedException e) {
            // 重新设置中断状态
            Thread.currentThread().interrupt();
            throw new IOException("元数据提取被取消", e);
        } catch (Exception e) {
            System.err.println("元数据提取失败: " + e.getMessage());
            e.printStackTrace();
            // 如果元数据提取失败，使用默认值
            song.setBpm(0.0); // 修改为0.0而不是120.0，表示检测失败
            song.setDuration(0); // 修改为0而不是默认3分钟
            // 生成默认鼓点偏移量
            song.setBeatOffset(0);
            // 返回song对象而不是抛出异常
            return song; // 注意：这里不保存到JSON文件
        }

        // 只有当BPM不为0时才将结果保存到JSON文件
        if (song.getBpm() > 0) {
            // 将结果保存到JSON文件
            try {
                JsonUtils.writeToJson(song, getJsonFilePath(audioFile));
            } catch (IOException e) {
                System.err.println("保存JSON文件失败: " + e.getMessage());
            }
        }

        return song;
    }

    /**
     * 获取BPMDetector中所有频带的BPM值
     *
     * @param detector BPMDetector实例
     * @return 所有BPM值的列表
     */
    private List<Double> getAllBPMs(BPMDetector detector) {
        // 使用BPMDetector提供的所有BPM候选值
        return detector.getAllBpmCandidates();
    }

    /**
     * 获取同名JSON文件路径
     *
     * @param audioFile 音频文件
     * @return JSON文件路径
     */
    private String getJsonFilePath(File audioFile) {
        String audioFileName = audioFile.getName();
        int lastDotIndex = audioFileName.lastIndexOf('.');
        if (lastDotIndex > 0) {
            audioFileName = audioFileName.substring(0, lastDotIndex);
        }
        return audioFile.getParent() + File.separator + audioFileName + ".json";
    }

    /**
     * 批量分析音频文件元数据（外部调用接口）
     *
     * @param audioFiles       音频文件列表
     * @param priority         任务优先级
     * @param progressCallback 进度回调
     */
    public void batchExtractMetadata(List<File> audioFiles, int priority, SongMetadataExtractor.AnalysisProgressCallback progressCallback) {
        // 使用任务调度器提交任务
        taskScheduler.submitTask(audioFiles, priority, progressCallback);
    }

    /**
     * 内部批量分析方法（由任务调度器调用）
     */
    public void batchExtractMetadataInternal(List<File> audioFiles, int priority, SongMetadataExtractor.AnalysisProgressCallback progressCallback) {
        // 检查songs是否为空，避免空指针异常
        if (songData == null) {
            songData = new HashMap<>();
        }
        // 检查audioFiles是否为空，避免空指针异常
        if (audioFiles == null) {
            audioFiles = new ArrayList<>();
        }
        // 检查哪些文件尚未分析或分析不完整
        List<File> filesToAnalyze = new ArrayList<>();
        for (File file : audioFiles) {
            // 查找已存在的song对象
            Song song = songData.get(file);
            if (song == null || song.getBpm() <= 0) {
                filesToAnalyze.add(file);
            }
        }
        // 如果没有需要分析的文件，直接返回
        if (filesToAnalyze.isEmpty()) {
            if (progressCallback != null) {
                progressCallback.onProgressUpdate("所有文件已分析完成", 100, null);
            }
            return;
        }

        // 创建一个SwingWorker来管理并行处理任务
        worker = new SwingWorker<List<Song>, File>() {
            private int totalFiles = filesToAnalyze.size();// 总文件数量
            private int processedFiles = 0;// 已处理文件数量

            @Override
            protected List<Song> doInBackground() throws Exception {
                // 根据是否已捐赠决定使用并行还是串行处理
                if (DonationDialog.hasDonated()) {
                    // 已捐赠用户使用并行处理
                    filesToAnalyze.parallelStream().forEach(file -> {
                        try {
                            // 检查任务是否已被取消
                            if (isCancelled()) {
                                System.out.println("任务被取消，跳过文件: " + file.getName());
                                return;
                            }

                            // 分析歌曲BPM
                            Song song = extractMetadata(file);
                            // 合并新分析的结果到songs列表中
                            songData.put(file, song);
                            progressCallback.onFileAnalysisComplete(file);
                            // 发布已完成的文件
                            publish(file);
                        } catch (Exception e) {
                            if (!isCancelled()) {
                                SwingUtilities.invokeLater(() -> {
                                    String message = "分析 " + file.getName() + " 时出错: " + e.getMessage();
                                    if (progressCallback != null) {
                                        progressCallback.onProgressUpdate(message, -1, file); // -1表示错误状态
                                    }
                                });
                                e.printStackTrace();
                            }
                        }
                    });
                } else {
                    // 未捐赠用户使用串行处理
                    for (File file : filesToAnalyze) {
                        try {
                            // 检查任务是否已被取消
                            if (isCancelled()) {
                                System.out.println("任务被取消，跳过文件: " + file.getName());
                                break;
                            }

                            // 分析歌曲BPM
                            Song song = extractMetadata(file);
                            // 合并新分析的结果到songs列表中
                            songData.put(file, song);
                            progressCallback.onFileAnalysisComplete(file);
                            // 发布已完成的文件
                            publish(file);

                            // 添加短暂延迟，避免未捐赠用户占用过多CPU资源
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException ie) {
                                Thread.currentThread().interrupt();
                                break;
                            }
                        } catch (Exception e) {
                            if (!isCancelled()) {
                                SwingUtilities.invokeLater(() -> {
                                    String message = "分析 " + file.getName() + " 时出错: " + e.getMessage();
                                    if (progressCallback != null) {
                                        progressCallback.onProgressUpdate(message, -1, file); // -1表示错误状态
                                    }
                                });
                                e.printStackTrace();
                            }
                        }
                    }
                }
                return null;
            }

            @Override
            protected void process(List<File> chunks) {
                // 检查任务是否已被取消
                if (isCancelled()) {
                    return;
                }

                // 更新每个已完成的文件的状态
                for (File file : chunks) {
                    processedFiles++;

                    // 通知UI更新单个文件的BPM显示
                    if (progressCallback != null) {
                        SwingUtilities.invokeLater(() -> {
                            progressCallback.onFileAnalysisComplete(file);
                        });
                    }

                    // 计算进度
                    int progress = (int) ((processedFiles * 100.0) / totalFiles);

                    // 更新状态信息
                    String message = "已完成 " + processedFiles + " / " + totalFiles + " 个文件的BPM分析";

                    if (progressCallback != null) {
                        progressCallback.onProgressUpdate(message, progress, file);
                    }
                }
            }

            @Override
            protected void done() {
                // 检查任务是否已被取消
                if (isCancelled()) {
                    return;
                }

                // 通知UI分析完成
                if (progressCallback != null) {
                    SwingUtilities.invokeLater(() -> {
                        progressCallback.onProgressUpdate("所有文件分析完成", 100, null);
                    });
                }
                // 调用任务完成回调
                if (progressCallback != null) {
                    progressCallback.onBPMTaskComplete();
                }

            }
        };
        worker.execute(); // 启动SwingWorker
    }

    public void batchExtractMetadata(Set<File> audioFiles, int priority, SongMetadataExtractor.AnalysisProgressCallback progressCallback) {
        batchExtractMetadata(new ArrayList<>(audioFiles), priority, progressCallback);
    }

    /**
     * 获取任务队列状态（用于调试和监控）
     */
    public String getTaskQueueStatus() {
        return taskScheduler.getQueueStatus();
    }

    /**
     * 停止所有任务
     */
    public void shutdown() {
        taskScheduler.shutdown();
        if (worker != null && !worker.isDone()) {
            worker.cancel(true);
        }
    }

    /**
     * 分析进度回调接口
     */
    public interface AnalysisProgressCallback {
        /**
         * 当进度更新时调用
         *
         * @param message     进度消息
         * @param progress    进度百分比
         * @param currentFile 当前正在分析的文件
         */
        void onProgressUpdate(String message, int progress, File currentFile);

        /**
         * 当单个文件分析完成时调用
         *
         * @param file 分析完成的文件
         */
        default void onFileAnalysisComplete(File file) {
        }

        ;

        /**
         * 当BPM分析任务完成时调用
         */
        default void onBPMTaskComplete() {
        }

        /**
         * 当其他任务完成时
         */
        default void onOtherTaskComplete() {
        }


    }
}